// ========== 头文件 ==========
#include <iostream>
#include <fstream>
#include <sstream>

#include <memory>
#include <iterator>
//#include <functional>

#include <vector>
#include <string>
#include <set>
#include <unordered_map>

#include <algorithm>    // 包含set_intersection

using namespace std;

// ========== 宏函数 ==========
#define ERROR_CHECK(cond, msg, cleanup) \
    do{ \
        if(cond) { \
            std::cerr << "Error:" << msg << "(" << __FILE__ << ":" << __LINE__ << ")" << std::endl; \
            cleanup; \
            return; \
        } \
    }while(0)

// ========== 前向声明 ==========
class QueryResult;  // 表示查询结果，通常与print联合使用
#if 0
class TextQuery;    // 将文本文件的内容保存在vector<string>中，返回QueryResult对象
class Query_base;   // eval相当于TextQuery的query函数，参数是TextQuery，返回QueryResult；rep函数用于返回查询的string表示形式
class Query;        // 用于获得shared_ptr，并且重载运算符
class WordQuery;
class NotQuery;
class BinaryQuery;
class AndQuery;
class OrQuery;
#endif

// ========== 具体实现1 ==========
class TextQuery{
private:
    shared_ptr<vector<string>> _text_vec_ptr;   // 共享指针内容

public:
    TextQuery(const string&);

    QueryResult query(const string&) const;

    shared_ptr<vector<string>> get_text_data() const;
};

class QueryResult{
friend class TextQuery;
private:
    shared_ptr<vector<string>> _text_vec_ptr;   // 共享指针内容
    shared_ptr<set<int>> _text_set_ptr;    // 此处可能会做与值运算，不建议单例与unique_ptr
    string _query_word;     // 唯一的作用：打印的时候显示

    //unordered_map<string, set<int>> _text_umap;

public:
    //QueryResult();  // 去掉默认函数，避免无参数查询
    QueryResult(shared_ptr<vector<string>>, shared_ptr<set<int>>, string);      // 需要string，否则print搞不清楚参数    
    //void printresult(const string&) const;
    void printresult() const;

    const shared_ptr<vector<string>>& get_text_data() const;
    const shared_ptr<set<int>>& get_matched_lines() const;
    const string& get_query_word() const;
};

class Query_base{
public:
    virtual ~Query_base() = default;    // 基类必须有虚析构函数
    // 纯虚函数接口
    virtual QueryResult eval(const TextQuery&) const = 0;
    virtual string rep() const = 0;     // 不接受参数，由子类自行维护状态

};

// 暂时考虑仅写Base, 用bind写，一步跳过调用指针
// 发现跳不过去，运算符的重载还指望Query实现
class Query{
private:
    shared_ptr<Query_base> _query_base_ptr;     // 不能直接实例化抽象类，只能通过指针或引用使用
    
public:
    explicit Query(const std::string& word);
    explicit Query(shared_ptr<Query_base>);
    
    QueryResult eval(const TextQuery& tq) const;
    string rep() const;

    shared_ptr<Query_base> get_query() const;   // 获取指针

    friend Query operator~(const Query&);
    friend Query operator&(const Query&, const Query&);
    friend Query operator|(const Query&, const Query&);
};

class WordQuery : public Query_base {
private:
    string _word;
public:
    WordQuery(const string&);

    QueryResult eval(const TextQuery&) const override;
    string rep() const override;
};

class NotQuery : public Query_base {
private:
    shared_ptr<Query_base> _query;
public:
    NotQuery(shared_ptr<Query_base> query);

    QueryResult eval(const TextQuery&) const override;
    string rep() const override;
};

class BinaryQuery : public Query_base {
protected:
    shared_ptr<Query_base> lhs, rhs;
    string op_symbol;

    BinaryQuery(shared_ptr<Query_base>, shared_ptr<Query_base>, string);
    string rep() const override;
};

class AndQuery : public BinaryQuery{
public:
    AndQuery(shared_ptr<Query_base>, shared_ptr<Query_base>);

    QueryResult eval(const TextQuery&) const override;
};

class OrQuery : public BinaryQuery{
public:
    OrQuery(shared_ptr<Query_base>, shared_ptr<Query_base>);

    QueryResult eval(const TextQuery&) const override;
};

// ========== 具体实现2 ==========
TextQuery::TextQuery(const string &filename)
    :_text_vec_ptr(make_shared<vector<string>>()){
    ifstream ifs(filename);
    ERROR_CHECK(!ifs.good(), "ifs is not good", ifs.close());
    
    string line;
    //size_t line_index = 0;
    while(getline(ifs, line)){
        _text_vec_ptr->push_back(line);
        
        //istringstream iss(line);
        //string word;
        
        //++line_index;
        //while(iss >> word){
            // _text_vec_ptr->push_back(word);
            // _text_umap.insert(word, line_index);     // 语法错误 
            // _text_umap[word].insert(line_index);
        //}
    }

    ifs.close();
}

#if 0
QueryResult TextQuery::query(const string& word) const{
    vector<string> _text_vec;
    unordered_map<string, set<int>> _text_umap;

    string line;
    size_t line_index = 0;
    for(auto &line : *_text_vec_ptr){
        istringstream iss(line);
        string text;

        ++line_index;
        //  while((iss >> text) && text == word){   // 此处逻辑会遗漏行内匹配
        while(iss >> text){
            if(text == word){
                _text_vec.emplace_back(line);
                _text_umap[word].insert(line_index);
                break;
            }
        }
    }
    
    return {_text_vec, _text_umap};
}
#endif
QueryResult TextQuery::query(const string& word) const{
    auto _set = make_shared<set<int>>();
    //auto _vec = make_shared<vector<string>>();

    string line;
    size_t line_index = 0;
    for(auto &line : *_text_vec_ptr){
        istringstream iss(line);
        string text;

        ++line_index;
        //  while((iss >> text) && text == word){   // 此处逻辑会遗漏行内匹配
        while(iss >> text){
            if(text == word){
   //             _vec->emplace_back(line);
                _set->insert(line_index);
                break;
            }
        }
    }
    
    //return {_vec, _set, word};
    return {_text_vec_ptr, _set, word};
}

shared_ptr<vector<string>> TextQuery::get_text_data() const{
    return _text_vec_ptr;
}

#if 0
// 直接在构造函数中修改求值
QueryResult::QueryResult(vector<string> text_vec, unordered_map<string, set<int>> text_umap)
    :_text_vec(text_vec)
    ,_text_umap(text_umap){}
#endif

QueryResult::QueryResult(shared_ptr<vector<string>> text_vec_ptr, shared_ptr<set<int>> text_set_ptr, string query_word)
    :_text_vec_ptr(text_vec_ptr)
    ,_text_set_ptr(text_set_ptr)
    ,_query_word(query_word){}

void QueryResult::printresult() const{
    cout << "查询单词: " << _query_word << "\n";
    cout << "出现次数: " << _text_set_ptr->size() << "\n";
    cout << "出现行号: ";
    for(auto& set_elem : *_text_set_ptr){
        cout << set_elem << " ";
    }
    cout << "\n";

#if 0
    for(auto& vec_elem : *_text_vec_ptr){
        cout << vec_elem << "\n";
    }
#endif
    for(auto& set_elem : *_text_set_ptr){
        cout << "(line" << set_elem << ") " << (*_text_vec_ptr)[set_elem-1] << "\n";
    }

    cout << "\n";
}

const shared_ptr<vector<string>>& QueryResult::get_text_data() const{
    return _text_vec_ptr;
}

const shared_ptr<set<int>>& QueryResult::get_matched_lines() const{
    return _text_set_ptr;
}

const string& QueryResult::get_query_word() const{
    return _query_word;
}

Query::Query(const std::string& word) 
    : _query_base_ptr(std::make_shared<WordQuery>(word)) {}

Query::Query(shared_ptr<Query_base> query_base_ptr)
    :_query_base_ptr(query_base_ptr){}

shared_ptr<Query_base> Query::get_query() const{
    return _query_base_ptr;
}

QueryResult Query::eval(const TextQuery& tq) const{
    return _query_base_ptr->eval(tq);
}
string Query::rep() const{
    return _query_base_ptr->rep();
}

Query operator~(const Query& operand){
    //return make_shared<NotQuery>(operand._query_base_ptr);
    //return Query(make_shared<NotQuery>(operand.get_query()));
    
    //1: 创建NotQuery对象
    //2：包装为Query对象
    //3：调用eval时，通过虚表找到NotQuery::eval
    return Query(make_shared<NotQuery>(operand._query_base_ptr));
}

Query operator&(const Query& lhs, const Query& rhs){
    return Query(make_shared<AndQuery>(lhs.get_query(), rhs.get_query()));
}

Query operator|(const Query& lhs, const Query& rhs){
    return Query(make_shared<OrQuery>(lhs.get_query(), rhs.get_query()));
}

WordQuery::WordQuery(const string& word)
    :_word(word){}

QueryResult WordQuery::eval(const TextQuery& tq) const{
    return tq.query(_word);
}

string WordQuery::rep() const{ 
    return _word; 
}

NotQuery::NotQuery(shared_ptr<Query_base> query)
    :_query(query){}

QueryResult NotQuery::eval(const TextQuery& tq) const{
    auto text_data = tq.get_text_data();
    auto total_lines = text_data->size();

    auto original_result = _query->eval(tq);
    auto original_set = original_result.get_matched_lines();

    //auto inverted_vec = make_shared<vector<string>>();
    auto inverted_set = make_shared<set<int>>();
    
    auto it = original_set->begin();
    for(size_t i = 1; i <= total_lines; ++i){
        if(it != original_set->end() && *it == static_cast<int>(i)){
            ++it;
        }else{
            inverted_set->insert(i);
            // inverted_vec->push_back(text_data[i]);
            //inverted_vec->push_back((*text_data)[i-1]);
        }
    }

    return QueryResult{
        text_data, //inverted_vec, 
        inverted_set, 
        "~" + original_result.get_query_word()
    };
}

string NotQuery::rep() const{
    return "~(" + _query->rep() + ")";
}

BinaryQuery::BinaryQuery(shared_ptr<Query_base> left, shared_ptr<Query_base> right, string symbol)
    :lhs(move(left))
    ,rhs(move(right))
    ,op_symbol(move(symbol)){}

string BinaryQuery::rep() const{
    return "(" + lhs->rep() + " " + rhs->rep() + ")";
}

AndQuery::AndQuery(shared_ptr<Query_base> left, shared_ptr<Query_base> right)
    : BinaryQuery(left, right, "&"){}

QueryResult AndQuery::eval(const TextQuery& tq) const{
    auto left_result = lhs->eval(tq);
    auto right_result = rhs->eval(tq);

    auto result_set = make_shared<set<int>>();
    set_intersection(
        left_result.get_matched_lines()->begin(),
        left_result.get_matched_lines()->end(),
        right_result.get_matched_lines()->begin(),
        right_result.get_matched_lines()->end(),
        inserter(*result_set, result_set->begin())
    );

    return QueryResult{
        left_result.get_text_data(),
        result_set,
        "(" + left_result.get_query_word() + " & " + right_result.get_query_word() + ")"   
    };   
}

OrQuery::OrQuery(shared_ptr<Query_base> left, shared_ptr<Query_base> right)
    : BinaryQuery(left, right, "|"){}

QueryResult OrQuery::eval(const TextQuery& tq) const{
    auto left_result = lhs->eval(tq);
    auto right_result = rhs->eval(tq);

    auto result_set = make_shared<set<int>>();
    set_union(
        left_result.get_matched_lines()->begin(),
        left_result.get_matched_lines()->end(),
        right_result.get_matched_lines()->begin(),
        right_result.get_matched_lines()->end(),
        inserter(*result_set, result_set->begin())
    );

    return QueryResult{
        left_result.get_text_data(),
        result_set,
        "(" + left_result.get_query_word() + " | " + right_result.get_query_word() + ")"   
    };   
}

// ========== 测试函数  ==========
void test_queryresult(){
    TextQuery tq("17_china_daily.txt");

    //tq.query("and");
    QueryResult qr = tq.query("and");
    //qr.printresult();
}

void test_word(){
    TextQuery tq("17_china_daily.txt");
    WordQuery wq("and");
    wq.eval(tq).printresult();
}

void test_not(){
    TextQuery tq("17_china_daily.txt");
    Query q = ~Query(make_shared<WordQuery>("and"));
    cout << q.rep() << endl;
    q.eval(tq).printresult();
}

void test_and(){
    TextQuery tq("17_china_daily.txt");
    Query q1(make_shared<WordQuery>("we"));
    Query q2(make_shared<WordQuery>("and"));
    auto and_q = q1 & q2;
    
    cout << and_q.rep() << endl;
    and_q.eval(tq).printresult();
}

void test_or(){
    TextQuery tq("17_china_daily.txt");
    Query q1(make_shared<WordQuery>("is"));
    Query q2(make_shared<WordQuery>("and"));
    auto or_q = q1 | q2;
    
    cout << or_q.rep() << endl;
    or_q.eval(tq).printresult();
}

void test_all(){
    TextQuery tq("17_china_daily.txt");
    auto complex_q = (Query("is") | Query("and")) & ~Query("the");
    complex_q.eval(tq).printresult();
    std::cout << "查询表达式: " << complex_q.rep() << std::endl;
}

int main()
{
    test_queryresult();
    test_word();
    test_not();
    test_and();
    test_or();
    test_all();
    return 0;
}

